#!/usr/bin/env luajit
-- -*- lua -*-
--
-- Copyright (C) 2014-2020 Markus Klotzbuecher <mk@mkio.de>
--
-- SPDX-License-Identifier: BSD-3-Clause
--

ubx = require("ubx")
bd = require("blockdiagram")
local utils = require("utils")
local ts = tostring

local function usage()
   local res, str = utils.preproc(
	    [=[
microblx function block model system launcher
usage: ubx-launch [OPTION] -c <model file>
  -b BLOCK		monitor BLOCK and shutdown when it becomes inactive
  -c FILE[,FILE2]	.usc or .json model file to launch
			if multiple models are given, these will be merged prior
			to launching.
  -ctype TYPE[,TYPE2]	types of the model file. Either ucs or json. If not specified,
			auto-detected from extension
  -nodename NAME	set nodename to NAME
  -mlockall		call mlockall to lock memory
  -dumpable             enable core dumps even for priviledged processes
  -nostart		instantiate and configure, but don't start
  -t SECONDS		run for SECONDS and then shutdown
  -loglevel N		set global loglevel [0..7]
  -s			log to stderr (in addition to ubx_log)
  -v                    verbose (will log additional, early messages to stderr)
  -webif [PORT]		create and start webinterface block.
			the optional port defaults to 8888.

  -validate             don't run, just validate configuration file

  -check CHK1[,CHK2]    carry out additional validation
    available checks:
@   for k,v in pairs(checks) do
      $(k): $(v.desc)
@   end

  -werror		treat warnings as errors
  -version		print version and exit
  -h			display this help and exit
]=], {checks=bd._checks, pairs=pairs, table=table})
   assert(res, "failed to generate usage string")
   print(str)
end

local function isempty(s)
  return s == nil or s == ''
end

local opttab=utils.proc_args(arg)
local nodename
local model
local conf_files
local conf_types = {}
local monitorblock
local checks
local loglevel

if opttab['-version'] then
   print("microblx "..ubx.safe_tostr(ubx.version()))
   os.exit(0)
end

if #arg==1 or opttab['-h'] then
   usage(); os.exit(1)
end

if not (opttab['-c'] and opttab['-c'][1]) then
   print("error: no configuration file(s) given (-c option)")
   os.exit(1)
else
   conf_files = utils.split(opttab['-c'][1], ',')
end

if opttab['-v'] then bd.VERBOSE=true end

if opttab['-ctype'] then
    if not opttab['-ctype'][1] then
        print("error: -ctype option requires a type argument")
        os.exit(1)
    else
       conf_types = utils.split(opttab['-ctype'][1], ',')
    end
    if #conf_files ~= #conf_types then
       print("error: the use of -ctype requires the same number of parameters as -c")
       os.exit(1)
    end
end

if (opttab['-b'] and opttab['-b'][1]) then
   monitorblock = opttab['-b'][1]
end

-- load first model and merge others into it
model = bd.load(conf_files[1], conf_types[1])

if not bd.is_system(model) then
   print(model)
   print("error: failed to load files "..table.concat(conf_files, ', '))
   os.exit(1)
end

for i=2,#conf_files do
   local m = bd.load(conf_files[i], conf_types[i])
   --   print("merging "..conf_files[i].. " into ".. conf_files[1])
   model:merge(m, true)
end

if opttab['-nodename'] then
   if not opttab['-nodename'][1] then
      print("error: -nodename option requires a node name argument)")
      os.exit(1)
   else
      nodename = opttab['-nodename'][1]
   end
end

if opttab['-validate'] then
   model:validate(true)
   os.exit(1)
end

if opttab['-loglevel'] then
   if not opttab['-loglevel'][1] then
      print("error: -loglevel option requres a level argument")
      os.exit(1)
   else
      loglevel = tonumber(opttab['-loglevel'][1])
   end
end

if opttab['-check'] then
   if not opttab['-check'][1] then
      print("error: -check option requires name argument)")
      os.exit(1)
   end
   checks = utils.split(opttab['-check'][1], ",")
end

local core_prefix, prefixes = ubx.get_prefix()
print("core_prefix: " .. core_prefix)
print("prefixes:    " .. table.concat(prefixes, ", "))

nd = model:launch{nodename=nodename,
		  verbose=true,
		  loglevel=loglevel,
		  use_stderr=opttab['-s'],
		  mlockall=opttab['-mlockall'],
		  dumpable=opttab['-dumpable'],
		  nostart=opttab['-nostart'],
		  checks=checks or nil,
		  werror=opttab['-werror'],
}

if opttab['-webif'] then
   local port = opttab['-webif'][1] or 8888
   print("starting up webinterface block (http://localhost:"..ts(port)..")")
   ubx.load_module(nd, "webif")
   local webif1=ubx.block_create(nd, "ubx/webif", "webif1", { port=ts(port) })
   assert(ubx.block_init(webif1)==0)
   assert(ubx.block_start(webif1)==0)
end

if not opttab['-i'] then
   local duration = math.huge
   local monblock = nil

   if opttab['-t'] then
      if not opttab['-t'][1] then
         print("no time given (-t option)")
         os.exit(1)
      else
         duration = tonumber(opttab['-t'][1])
      end
   end

   if not isempty(monitorblock) then
      monblock = nd:block_get(monitorblock)
   end

   while duration > 0 do
      duration = duration - 1

      if ubx.wait_sigint(1) == 0 then
	 print("received signal, shutting down")
	 break
      end
      if monblock and monblock:get_block_state() ~= 'active' then
	 break
      end
   end
   model:pulldown(nd)
end

